(PYTHON) Day - 17 Collections(2)

Reference

  • 문제 출처 - HackerRank
  • 파이썬 연습 - Practice - Python

개인적인 생각과 상상으로 작성한 내용들이 포함되어 있습니다
문제를 풀고 Discussion Tab을 참고하며 코드 스타일을 개선하려고 노력하고자 합니다


HackerRank


Collections


collections.Counter()


문제 : 신발 가게가 신발을 판매해서 번 수입을 구하는 문제
입력 : 신발 개수 X; (X 반복) 보유한 신발 사이즈; 손님 수 N; (N 반복) 구매한 신발의 사이즈, 가격;
출력 : 총 매출

10
2 3 4 5 6 8 7 6 5 18
6
6 55
6 45
6 55
4 40
18 60
10 50

200

고객들의 구매내용도 미리 입력받고 계산하려고 했지만 반복문을 돌리기 까다로워서 입력시 바로바로 처리하는 식으로 구현. 굳이 Counter 모듈을 사용하지 않아도 풀리는 문제

X = int(input())
shoes = [int(size) for size in input().split()]
N = int(input())

# customers = {int(size): price for (size, price) in (input().split() for \_ in range(N))}

earned = 0

for \_ in range(N):
size, price = map(int, input().split())
if size in shoes:
earned += price
shoes.remove(size)

print(earned)

Counter 모듈을 사용한 구현

from collections import Counter

X = int(input())
shoes = [int(size) for size in input().split()]
N = int(input())
shoes_counter = Counter(shoes)
earned = 0

for \_ in range(N):
size, price = map(int, input().split())
if shoes_counter[size] > 0:
earned += price
shoes_counter[size] -= 1

print(earned)

DefaultDict Tutorial


문제 : 그룹 B의 각 문자들이 그룹 A에서 몇 번 나타나는지 구하는 문제
입력 : 그룹 A의 문자 수 n, 그룹 B의 문자수 m; (n 반복) 그룹 A 문자들; (m 반복) 그룹 B 문자들;
예제 : 그룹 A는 (a, a, b, a, b) 그룹 B는 (a, b)이다
그룹 A에서 ‘a’는 (1 2 4) 위치에 ‘b’는 (3 5) 위치에 있다

defaultdict() 함수는 딕셔너리에 특정 key 값에 value를 더할 때(append) 유용하게 사용된다.
딕셔너리의 기본 내장함수인 dict.update() 는 기존의 값을 덮어버리기 때문에 추가로 삽입이 필요할 때 사용한다.

from collections import defaultdict

d = defaultdict(list)
d['python'].append("awesome")
d['something-else'].append("not relevant")
d['python'].append("language")
for i in d.items():
print(i)

# 딕셔너리 사용
f = dict()
f.update({'PY': 'AWSOME'})
f.update({'PY': 'NOT RELEVANT'}) # 기존의 것을 덮어버린다
print(f)
('python', ['awesome', 'language'])
('something-else', ['not relevant'])
{'PY': 'NOT RELEVANT'}

5 2
a
a
b
a
b
a
b

1 2 4
3 5

from collections import defaultdict

n, m = map(int, input().split())
gA = defaultdict(list)

for i in range(1, n+1):
gA[input()].append(i)

for \_ in range(m):
b = input()
if b in gA.keys():
print(\*gA[b])
else:
print(-1)

매우 깔끔하게 정리해 놓은 코드

from collections import defaultdict

# Inputs

# ------

n, m = map(int, input().split(' '))

# Let's get the groups as lists

# -----------------------------

#input1 = ['a', 'a', 'b', 'a', 'b']
#input2 = ['a', 'b']
input1 = list()
for i in range(n):
input1.append(input())

input2 = list()

for i in range(m):
input2.append(input())

# Calculate Output

# ----------------

d = defaultdict(list)

# Fill d with input1 values

for i in range(n):
d[input1[i]].append(i+1)
#print(d) --> defaultdict(<class 'list'>, {'a': [1, 2, 4], 'b': [3, 5]})

# Apply the logic for printing

for i in input2:
if i in d:
print(\*d[i])
else:
print(-1)

collections.namedtuple()


문제 : 주어진 datasheet에서 학생들의 성적(marks)의 평균을 구하는 문제
입력 : (입력 데이터 참고)
출력 : 평균을 소수점 2번째 자리까지 표현

5
ID MARKS NAME CLASS
1 97 Raymond 7
2 50 Steven 4
3 91 Adrian 9
4 72 Stewart 5
5 80 Peter 6

78.00

5
MARKS CLASS NAME ID
92 2 Calum 1
82 5 Scott 2
94 2 Jason 3
55 8 Glenn 4
82 2 Fergus 5

81.00

굳이 파이썬을 사용하며 짧은 코드를 구현할 수 있다고 해도… 굳이 가독성이 떨어지게 그래야하나 싶다. 아래 코드도 정상적으로 작동하나 해당 컴파일러는 4줄 이내로 문제 해결을 요구한다.

from collections import namedtuple

num_of_std = int(input())
attribute = input().split()
students = namedtuple('students', attribute)
total = 0

for \_ in range(num_of_std):
student = students(\*input().split())
total += int(student.MARKS)

print('{:.2f}'.format(total/num_of_std))
from collections import namedtuple
n, Student = int(input()), namedtuple('Student', input())
print("{:.2f}".format(sum([int(Student(*input().split()).MARKS) for _ in range(n)]) / n))

2줄로 끝내는 이 코드는 조금 신박하다

n,ind=int(input()),(input().split()).index('MARKS')
print(sum([float((input().split())[ind]) for i in range(n)])/n,end="0")

collections.OrderedDict()


문제 : 마켓에서 소비자가 구매해간 물건과 가격을 종합하는 문제
입력 : 구매내역 개수 N; (N 반복) 물품 이름, 가격;
출력 : 물품 이름, 가격을 순서대로 출력

9
BANANA FRIES 12
POTATO CHIPS 30
APPLE JUICE 10
CANDY 5
APPLE JUICE 10
CANDY 5
CANDY 5
CANDY 5
POTATO CHIPS 30

BANANA FRIES 12
POTATO CHIPS 60
APPLE JUICE 20
CANDY 20

try/except 문으로 해당 아이템의 유무에 따른 행동을 다르게 했다

from collections import OrderedDict

N = int(input())
items = OrderedDict()

for i in range(N):
\*it, price = input().split()
item = ' '.join(it)
try:
items[item] += int(price)
except KeyError:
items[item] = int(price)

for item, price in items.items():
print(item, price)

dict.get() 함수를 사용해서 기본값을 지정해서 해결하는 방법도 있다

from collections import OrderedDict

N = int(input())
items = OrderedDict()

for i in range(N):
\*it, price = input().split()
item = ' '.join(it)
items[item] = items.get(item, 0) + int(price)

for item, price in items.items():
print(item, price)

Word Order


문제 : 서로 다른 문자열이 몇 개인지 구하는 문제
입력 : 입력받을 개수 N; (N 반복) 문자열 입력;
출력 : 서로 다른 문자열의 수; 각 문자열의 개수;
예제 : ‘bcdef’는 2번 출현하고 나머지 ‘abcdefg’, ‘bcde’는 각 1번씩 출현

4
bcdef
abcdefg
bcde
bcdef

3
2 1 1

from collections import Counter

N = int(input())
words = [input() for _ in range(N)]
words_counter = Counter(words)

print(len(words_counter))
print(\*words_counter.values())

collections.deque()


문제 : deque를 생성하고 각 명령어를 수행한 뒤 결과값을 출력하는 문제
입력 : 명령어 개수 N; (N 반복) 명령어, 값;
출력 : deque에 있는 요소들

6
append 1
append 2
append 3
appendleft 4
pop
popleft

1 2

eval() 함수를 사용하려면 조금 까다로운듯…

from collections import deque
d = deque()
for \_ in range(int(input())):
eval('d.{0}({1})'.format(*input().split(), ''))
print(*d)

getattr() 함수를 사용해서 명령어 수행

from collections import deque

N = int(input())
d = deque()

for \_ in range(N):
method, *arg = input().split()
getattr(d, method)(*arg)

print(\*d)


문제 : 문자열에서 가장 빈도수가 높은 단어 3개를 출력하는 문제
입력 : 문자열
출력 : 문자, 문자 수

aabbbccde

b 3
a 2
c 2

from collections import Counter

words = Counter(sorted(input()))
[print(*w) for w in words.most_common(3)]

Piling Up!


문제 : 특정 규칙을 만족하면서 큐브를 쌓을 수 있는지 확인하는 문제
입력 : 테스트케이스 수 T; (큐브의 수 n; 각 큐브의 가로길이;)
출력 : Yes/No 로 출력
예제 : 큐브는 왼쪽/오른쪽 끝에서만 먼저 가져올 수 있으며 밑에 깔리는 큐브의 길이가 더 길어야 한다.
첫번째 케이스에서는 4-4-3-3-2-1 순으로 쌓을 수 있기에 Yes
두번째 케이스에서는 1위에 2나 3을 쌓을 수 없기에 No 가 된다

2
6
4 3 2 1 3 4
3
1 3 2

Yes
No

파이썬에서는 for-else 문을 사용할 수 있다.
for문이 끝까지 수행되면 else 문의 내용이 실행된다.

from collections import deque

for _ in range(int(input())):
_, queue = input(), deque(map(int, input().split()))

for cube in reversed(sorted(queue)):
if queue[-1] == cube:
queue.pop()
elif queue[0] == cube:
queue.popleft()
else:
print('No')
break
else:
print('Yes')
혹은 최소값을 기준으로 좌우 리스트를 분리하여 정렬된 값과 비교하는 방법도 있다<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">for</span> T <span class="keyword">in</span> range(int(input())):</span><br><span class="line">n, queue = input(), [int(i) <span class="keyword">for</span> i <span class="keyword">in</span> input().split()]</span><br><span class="line">min_idx = queue.index(min(queue))</span><br><span class="line">left_q = queue[:min_idx]</span><br><span class="line">right_q = queue[min_idx+<span class="number">1</span>:]</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> left_q == sorted(left_q, reverse=<span class="literal">True</span>) <span class="keyword">and</span> right_q == sorted(right_q):</span><br><span class="line">    print(<span class="string">"Yes"</span>)</span><br><span class="line"><span class="keyword">else</span>:</span><br><span class="line">    print(<span class="string">"No"</span>) </span><br></pre></td></tr></table></figure>